#include "gd32h7xx.h"
#include "bsp_i2s.h"

#define ARRAYSIZE         128

uint32_t sai_send_array[ARRAYSIZE];
uint32_t sai_receive_array[ARRAYSIZE];


static void bsp_sai_gpio_config(void);
static void bsp_sai_config(void);
static void bsp_dma_config(void);

void bsp_i2s_init(void)
{
    bsp_sai_gpio_config();
    bsp_sai_config();
    bsp_dma_config();
}

static void bsp_sai_gpio_config(void)
{
    gpio_af_set(GPIOE, GPIO_AF_6, GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_NONE,GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_100_220MHZ,GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6);
}

static void bsp_sai_config(void)
{
    sai_parameter_struct sai_structure;
    sai_frame_parameter_struct sai_frame_structure;
    sai_slot_parameter_struct sai_slot_structure;

    sai_struct_para_init(&sai_structure);
    sai_frame_struct_para_init(&sai_frame_structure);
    sai_slot_struct_para_init(&sai_slot_structure);

    /* initialize SAI0_B0 frame */
    sai_frame_structure.frame_width            = 64;
    sai_frame_structure.frame_sync_width       = 32;
    sai_frame_structure.frame_sync_function    = SAI_FS_FUNC_START_CHANNEL;
    sai_frame_structure.frame_sync_polarity    = SAI_FS_POLARITY_LOW;
    sai_frame_structure.frame_sync_offset      = SAI_FS_OFFSET_BEGINNING;
    sai_frame_init(SAI0, SAI_BLOCK0, &sai_frame_structure);

    /* initialize SAI0_B0 slot */
    sai_slot_structure.slot_number             = 2;
    sai_slot_structure.slot_width              = SAI_SLOT_WIDTH_32BIT;
    sai_slot_structure.data_offset             = 0;
    sai_slot_structure.slot_active             = SAI_SLOT_ACTIVE_ALL;
    sai_slot_init(SAI0, SAI_BLOCK0, &sai_slot_structure);

    /* initialize SAI0_B0  */
    sai_structure.operating_mode               = SAI_MASTER_TRANSMITTER;
    sai_structure.protocol                     = SAI_PROTOCOL_POLYMORPHIC;
    sai_structure.data_width                   = SAI_DATAWIDTH_32BIT;
    sai_structure.shift_dir                    = SAI_SHIFT_MSB;
    sai_structure.sample_edge                  = SAI_SAMPEDGE_RISING;
    sai_structure.sync_mode                    = SAI_SYNCMODE_ASYNC;
    sai_structure.output_drive                 = SAI_OUTPUT_WITH_SAIEN;
    sai_structure.clk_div_bypass               = SAI_CLKDIV_BYPASS_OFF;
    sai_structure.mclk_div                     = SAI_MCLKDIV_1;
    sai_structure.mclk_oversampling            = SAI_MCLK_OVERSAMP_256;
    sai_structure.mclk_enable                  = SAI_MCLK_ENABLE;
    sai_structure.fifo_threshold               = SAI_FIFOTH_EMPTY;
    sai_init(SAI0, SAI_BLOCK0, &sai_structure);

    /* initialize SAI0_B1 frame */
    sai_frame_init(SAI0, SAI_BLOCK1, &sai_frame_structure);
    /* initialize SAI0_B1 slot */
    sai_slot_init(SAI0, SAI_BLOCK1, &sai_slot_structure);
    /* initialize SAI0_B1 */
    sai_structure.operating_mode               = SAI_SLAVE_RECEIVER;
    sai_structure.sync_mode                    = SAI_SYNCMODE_OTHERBLOCK;
    sai_init(SAI0, SAI_BLOCK1, &sai_structure);
}

static void bsp_dma_config(void)
{
    dma_single_data_parameter_struct dma_init_struct;
    /* initialize DMA0 channel 0 */
    dma_deinit(DMA0, DMA_CH0);
    /* initialize DMA1 channel 1 */
    //dma_deinit(DMA1, DMA_CH1);

    dma_single_data_para_struct_init(&dma_init_struct);
    /* configure SAI0_B0 transmit dma: DMA0_CH0 */
    dma_init_struct.request             = DMA_REQUEST_SAI0_B0;
    dma_init_struct.direction           = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr        = (uint32_t)sai_send_array;
    dma_init_struct.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
    dma_init_struct.number              = ARRAYSIZE;
    dma_init_struct.periph_addr         = (uint32_t)(&SAI_DATA(SAI0, SAI_BLOCK0));
    dma_init_struct.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority            = DMA_PRIORITY_ULTRA_HIGH;
    dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);

    /* configure SAI0_B1 recevie dma: DMA0_CH1 */
    dma_init_struct.request             = DMA_REQUEST_SAI0_B1;
    dma_init_struct.direction           = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr        = (uint32_t)sai_receive_array;
    dma_init_struct.memory_inc          = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_32BIT;
    dma_init_struct.number              = ARRAYSIZE;
    dma_init_struct.periph_addr         = (uint32_t)(&SAI_DATA(SAI0, SAI_BLOCK1));
    dma_init_struct.periph_inc          = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.priority            = DMA_PRIORITY_LOW;
    dma_single_data_mode_init(DMA0, DMA_CH1, &dma_init_struct);
}